home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / libs / unixlib.lha / unix / src / amigados.c < prev    next >
C/C++ Source or Header  |  1996-10-18  |  7KB  |  329 lines

  1. #include "amiga.h"
  2. #include "files.h"
  3. #include "signals.h"
  4. #include <exec/memory.h>
  5. #include <fcntl.h>
  6. #include <sys/termios.h>
  7. #include <amiga/ioctl.h>
  8. #include <string.h>
  9.  
  10. void _fail(char *format,...);
  11.  
  12. /* Code for fd's describing AmigaDOS files */
  13.  
  14. struct amigainfo {
  15.     BPTR fh;
  16.     BPTR lock;              /* A lock on the file (may be null) */
  17.     long protection;        /* To be set when file is closed, -1 for none */
  18.     char interactive;       /* True if file was interactive */
  19.     char deleted;           /* True if file has been deleted but not closed */
  20. };
  21.  
  22. static ULONG file_select_start(void *userinfo, int rd, int wr, int ex)
  23. {
  24.     /* If read or write, input always immediately available, gniark */
  25.     if (rd || wr)
  26.     return (ULONG) - 1;
  27.     return 0;
  28. }
  29.  
  30. static int file_select_poll(void *userinfo, int *rd, int *wr, int *ex)
  31. {
  32.     /* Input always immediately available, gniark */
  33.     *ex = 0; /* we don't detect 'exceptional' conditions */
  34.     return 0;
  35. }
  36.  
  37. static int file_read(void *userinfo, void *buffer, unsigned int length)
  38. {
  39.     struct amigainfo *info = userinfo;
  40.     BPTR fh = info->fh;
  41.     LONG cnt;
  42.  
  43.     if (info->deleted)
  44.     return 0;
  45.     if ((cnt = Read(fh, buffer, length)) == -1)
  46.     ERROR;
  47.     return (int) cnt;
  48. }
  49.  
  50. static int file_write(void *userinfo, void *buffer, unsigned int length)
  51. {
  52.     struct amigainfo *info = userinfo;
  53.     BPTR fh = info->fh;
  54.     int cnt;
  55.  
  56.     if (info->deleted)
  57.     return 0;
  58.     if (info->interactive) {
  59.     char *bufend = (char *) buffer + length;
  60.  
  61.     /* Write by lines, more pleasant for user */
  62.     cnt = 0;
  63.     while (length) {
  64.         char *end = buffer;
  65.         long nb;
  66.         unsigned len;
  67.  
  68.         while (end < bufend && *end != '\n')
  69.         end++;
  70.  
  71.         if (end == bufend)
  72.         len = end - (char *) buffer;
  73.         else
  74.         len = end + 1 - (char *) buffer;
  75.  
  76.         if ((nb = Write(fh, buffer, len)) == -1)
  77.         ERROR;
  78.  
  79.         cnt += nb;
  80.         if (nb != len)
  81.         break;
  82.  
  83.         buffer = end + 1;
  84.         length -= nb;
  85.         /* Interrupt write ? */
  86.         if (_handle_signals(_check_signals(0)))
  87.         break;
  88.     }
  89.     } else if ((cnt = Write(fh, buffer, length)) == -1)
  90.     ERROR;
  91.     return cnt;
  92. }
  93.  
  94. static int file_lseek(void *userinfo, long rpos, int mode)
  95. {
  96.     struct amigainfo *info = userinfo;
  97.     BPTR fh = info->fh;
  98.     LONG pos, err;
  99.  
  100.     if (info->deleted)
  101.     return 0;
  102.     pos = Seek(fh, rpos, mode - 1);
  103.     err = IoErr();
  104.     if (pos == -1 || err) {
  105.     errno = convert_oserr(err);
  106.     return -1;
  107.     }
  108.     pos = Seek(fh, 0, OFFSET_CURRENT);
  109.     if (pos == -1 || err) {
  110.     errno = convert_oserr(err);
  111.     return -1;
  112.     }
  113.     return pos;
  114. }
  115.  
  116. static int file_close(void *userinfo, int internal)
  117. {
  118.     struct amigainfo *info = userinfo;
  119.     BPTR fh = info->fh;
  120.     long protection = info->protection;
  121.     char name[256];
  122.     int ok, deleted;
  123.  
  124.     if (info->lock)
  125.     UnLock(info->lock);
  126.     deleted = info->deleted;
  127.     free(info);
  128.     if (deleted)
  129.     return 0;
  130.  
  131.     ok = NameFromFH(fh, name, 256);
  132.     if (internal || Close(fh))
  133.     if (!ok || protection == -1 || SetProtection(name, protection))
  134.         return 0;
  135.     ERROR;
  136. }
  137.  
  138. static int isfifo(BPTR fh)
  139. /* Requires: IsInteractive(fh) */
  140. /* Try & find out if fh is a fifo: file */
  141. {
  142.     WaitForChar(fh, 0);
  143.     return (IoErr() == ERROR_ACTION_NOT_KNOWN);
  144. }
  145.  
  146. static int GetWinBounds(BPTR fh, long *width, long *height)
  147. {
  148.     char buffer[16];
  149.     int ok = 0;
  150.  
  151.     if (!isfifo(fh) && SetMode(fh, 1)) {
  152.     if ((Write(fh, "\x9b" "0 q", 4) == 4) &&
  153.         WaitForChar(fh, 10000L) &&
  154.         (Read(fh, buffer, sizeof(buffer)) > 9) &&
  155.         (buffer[0] == '\x9b')) {
  156.         int y = StrToLong(buffer + 5, height);
  157.         int x = StrToLong(buffer + 5 + y + 1, width);
  158.         if ((x != -1) && (y != -1))
  159.         ok = 1;
  160.     }
  161.     SetMode(fh, 0);
  162.     }
  163.     return ok;
  164. }
  165.  
  166. int _do_truncate(BPTR fh, off_t length)
  167. {
  168.     int err, ret = -1;
  169.     long oldsize, oldpos;
  170.  
  171.     oldpos = Seek(fh, 0, OFFSET_END);
  172.     oldsize = Seek(fh, 0, OFFSET_END);
  173.  
  174.     if (!(err = IoErr()) &&
  175.     SetFileSize(fh, length, OFFSET_BEGINNING) == length) {
  176.     if (oldsize < length) {
  177.         /* Zero extra bytes */
  178.         off_t bufsize = length - oldsize, left = bufsize;
  179.         char *buf;
  180.         char reserve[512];
  181.  
  182.         if (!(buf = AllocMem(bufsize, MEMF_CLEAR))) {
  183.         bufsize = AvailMem(MEMF_LARGEST) / 2;
  184.  
  185.         if (bufsize < 512 || !(buf = AllocMem(bufsize, MEMF_CLEAR))) {
  186.             bufsize = 512;
  187.             buf = reserve;
  188.             memset(reserve, 0, 512);
  189.         }
  190.         }
  191.         while (left > 0) {
  192.         long count = left > bufsize ? bufsize : left;
  193.  
  194.         __chkabort();
  195.         if (Write(fh, buf, count) != count) {
  196.             err = IoErr();
  197.             break;
  198.         }
  199.         left -= count;
  200.         }
  201.         if (buf != reserve)
  202.         FreeMem(buf, bufsize);
  203.     }
  204.     if (!err)
  205.         ret = 0;
  206.     }
  207.     if (oldpos < length)
  208.     Seek(fh, oldpos, OFFSET_BEGINNING);
  209.  
  210.     if (ret)
  211.     errno = convert_oserr(err);
  212.     return ret;
  213. }
  214.  
  215. static int file_ioctl(void *userinfo, int request, void *data)
  216. {
  217.     struct amigainfo *info = userinfo;
  218.     BPTR fh = info->fh;
  219.  
  220.     if (!info->deleted) {
  221.     switch (request) {
  222.         case TIOCGWINSZ: {
  223.         struct winsize *ws = data;
  224.         long col, row;
  225.  
  226.         if (info->interactive && GetWinBounds(fh, &col, &row)) {
  227.             ws->ws_col = col;
  228.             ws->ws_row = row;
  229.             return 0;
  230.         }
  231.         errno = ENOTTY;
  232.         return -1;
  233.         }
  234.         case _AMIGA_INTERACTIVE: {
  235.         int *inter = data;
  236.  
  237.         *inter = IsInteractive(fh);
  238.         return 0;
  239.         }
  240.         case _AMIGA_GET_FH: {
  241.         BPTR *gotfh = data;
  242.  
  243.         *gotfh = fh;
  244.         return 0;
  245.         }
  246.         case _AMIGA_FREE_FH:
  247.         return 0;
  248.         case _AMIGA_TRUNCATE: {
  249.         off_t length = *(off_t *) data;
  250.  
  251.         return _do_truncate(fh, length);
  252.         }
  253.         case _AMIGA_SETPROTECTION:
  254.         info->protection = *(long *) data;
  255.         return 0;
  256.         case _AMIGA_DELETE_IF_ME: {
  257.         BPTR nlock = *(BPTR *) data;
  258.  
  259.         if (!info->lock)
  260.             info->lock = DupLockFromFH(info->fh);
  261.         if (info->lock && SameLock(nlock,info->lock) == LOCK_SAME) {
  262.             char name[256];
  263.  
  264.             if (NameFromFH(fh, name, 256)) {
  265.             UnLock(nlock);
  266.             UnLock(info->lock);
  267.             Close(fh);
  268.             SetProtection(name, 0);
  269.             info->deleted = TRUE;
  270.             info->lock = info->fh = 0;
  271.             if (DeleteFile(name))
  272.                 return 0;
  273.             }
  274.         }
  275.         ERROR;
  276.         }
  277.         case _AMIGA_IS_FIFO: {
  278.             int *is_fifo = data;
  279.  
  280.         *is_fifo = FALSE;
  281.         return 0;
  282.         }
  283.         case _AMIGA_IS_SOCK: {
  284.             int *is_sock = data;
  285.  
  286.         *is_sock = FALSE;
  287.         return 0;
  288.         }
  289.     }
  290.     }
  291.     errno = EINVAL;
  292.     return -1;
  293. }
  294.  
  295. int _alloc_amigafd(BPTR fh, long protection, long flags)
  296. {
  297.     struct amigainfo *new = malloc(sizeof(struct amigainfo));
  298.     int fd;
  299.  
  300.     if (!new) {
  301.     errno = ENOMEM;
  302.     return -1;
  303.     }
  304.     new->fh = fh;
  305.     new->lock = NULL;
  306.     new->protection = protection;
  307.     new->deleted = FALSE;
  308.     new->interactive = IsInteractive(fh);
  309.  
  310.     fd = _alloc_fd(new, flags,
  311.            file_select_start, file_select_poll, file_read, file_write,
  312.            file_lseek, file_close, file_ioctl);
  313.     if (fd < 0)
  314.     free(new);
  315.  
  316.     return fd;
  317. }
  318.  
  319. void _init_unixio(BPTR in, int close_in, BPTR out, int close_out,
  320.           BPTR err, int close_err)
  321. {
  322.     if (_alloc_amigafd(in,  -1, FI_READ  | (close_in  ? 0 : O_NO_CLOSE)) == 0 &&
  323.     _alloc_amigafd(out, -1, FI_WRITE | (close_out ? 0 : O_NO_CLOSE)) == 1 &&
  324.     _alloc_amigafd(err, -1, FI_WRITE | (close_err ? 0 : O_NO_CLOSE)) == 2)
  325.     return;
  326.  
  327.     _fail("Failed to initialise I/O");
  328. }
  329.